home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 June / CHIP_CD_2004-06.iso / software / miranda_hit / files / mirinstsetup.exe / Miranda Installer 0.0.1.2 / Worker.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-04-20  |  36.4 KB  |  1,135 lines

  1. /*
  2.     Miranda Installer - Installs nightlies and Miranda addons.
  3.     Copyright (C) 2002-2003 Goblineye Entertainment
  4.  
  5.     Authors: Saar (Tornado) and Kai (kai_b)
  6.  
  7.     This program is free software; you can redistribute it and/or modify
  8.     it under the terms of the GNU General Public License as published by
  9.     the Free Software Foundation; either version 2 of the License, or
  10.     (at your option) any later version.
  11.  
  12.     This program is distributed in the hope that it will be useful,
  13.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.     GNU General Public License for more details.
  16.  
  17.     You should have received a copy of the GNU General Public License
  18.     along with this program; if not, write to the Free Software
  19.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20. */
  21.  
  22. #include "Worker.h"
  23. #pragma hdrstop
  24.  
  25.  
  26.  
  27. // handle the file pattern, we might need to create subdirectories for this file
  28. // we do not write the file though, we just create directories and such
  29. // szFilename is filename reported from Zip entry, szDestDir is the destination directory
  30. __forceinline void Handle_File_Pattern(const char *szFilename,const char *szDestDir)
  31. {
  32.     const char *lpNS = szFilename;
  33.  
  34.     char szMD[MAX_PATH + 1];
  35.     char szComp[MAX_PATH + 1]; // component of directory tree
  36.     lpNS = strchr(lpNS,'\\');
  37.     while (lpNS != NULL) // find the next one
  38.     {
  39.         lstrcpy(szMD,szDestDir);
  40.         lstrcat(szMD,"\\");
  41.         
  42.         lstrcpyn(szComp,szFilename,lpNS - szFilename + 1);
  43. //        szComp[lpNS - szFilename] = '\0';
  44.  
  45.         lstrcat(szMD,szComp); // add it
  46.         CreateDirectory(szMD,NULL); // create it
  47.  
  48.         lpNS = strchr(lpNS+1,'\\');
  49.     }
  50. }
  51.  
  52.  
  53.  
  54. __forceinline void Validate_Directory(const char *szDirectory) // make sure directory exists
  55. {
  56.     const char *lpSlash = strchr(szDirectory,'\\');
  57.     char szTemp[MAX_PATH + 1];
  58.     while (lpSlash != NULL)
  59.     {
  60.         // btw: last char can't be a slash (we prevent it)
  61.         lstrcpyn(szTemp,szDirectory,lpSlash - szDirectory + 1); // don't copy the slash
  62.         CreateDirectory(szTemp,NULL);
  63.         lpSlash = strchr(lpSlash+1,'\\');
  64.     }
  65.     // now create final directory
  66.     CreateDirectory(szDirectory,NULL);
  67. }
  68.  
  69.  
  70.  
  71. // does the actual dirty dirty work of installing the current file in the .zip (The function takes care of opening it and closing it later)
  72. // this function needs to handle events such as: 1) the dest file already exists, and it is read-only. 2) sub-directories (That's actually handled by another function...)
  73. // *NO* errors are handled here!
  74. // NADA
  75. // the caller will be notified of the failure, and will show some warning on its own
  76. static bool Worker_InstallFile(unzFile hFile,HWND hwndDlg,int iItemID,const char *lpDestDir)
  77. {
  78.     char szDestFile[MAX_PATH + 1];
  79.     char szFilename[MAX_PATH + 1];
  80.  
  81.     unzGetCurrentFileInfo(hFile,NULL,szFilename,MAX_PATH+1,NULL,0,NULL,0);
  82.  
  83.     Validate_Directory(lpDestDir); // make sure directory exists
  84.  
  85.     // reverse slashes
  86.     Switch_Slashes(szFilename,false);
  87.  
  88.     if (*(szFilename + lstrlen(szFilename) - 1) != '\\') // meaning it's not a directory, we ignore directories
  89.     {
  90.         Handle_File_Pattern(szFilename,lpDestDir);
  91.  
  92.         lstrcpy(szDestFile,lpDestDir); // destination directory
  93.         lstrcat(szDestFile,"\\");
  94.         lstrcat(szDestFile,szFilename);
  95. /*
  96.         // this isn't needed
  97.         // read-only files can't be overwritten
  98.         // before we do anything, let's figure out if we're supposed to overwrite this file
  99.         if (g_WorkOptions.dwFlags & 1) // ask if to overwrite
  100.         {
  101.             DWORD dwAtts = GetFileAttributes(szDestFile);
  102.             if ((dwAtts != INVALID_FILE_ATTRIBUTES) && (dwAtts & FILE_ATTRIBUTE_READONLY)) // alert the user
  103.             {
  104.                 char szMsg[512];
  105.                 wsprintf(szMsg,"The read-only file %s already exists, would you like to overwrite it?",szDestFile);
  106.                 if (MessageBox(hwndDlg,szMsg,"buya",MB_ICONQUESTION | MB_YESNO) == IDNO)
  107.                 {
  108.                     return(true);
  109.                 }
  110.             }
  111.         }
  112. */
  113.         // notify the master thingy we're about to start extraction
  114.         // no need to strip the relative path from the filename
  115.         // it's kinda nice :)
  116.         SendMessage(hwndDlg,MIRINST_INFOMSG_EXTRACTING,iItemID,(LPARAM)szFilename);
  117.         if (unzOpenCurrentFile(hFile) != UNZ_OK)
  118.         {
  119.             return(false);
  120.         }
  121.  
  122.         FILE *hDecompFile = fopen(szDestFile,"wb");
  123.         if (hDecompFile != NULL)
  124.         {
  125.             char cData[2048];
  126.             while (1)
  127.             {
  128.                 int iRead = unzReadCurrentFile(hFile,cData,sizeof(cData));
  129.  
  130.                 if (iRead > 0)
  131.                 {
  132.                     if (fwrite(cData,1,iRead,hDecompFile) != (unsigned int)iRead)
  133.                     {
  134.                         // problems, bahh
  135.                         unzCloseCurrentFile(hFile);
  136.                         fclose(hDecompFile);
  137.                         DeleteFile(szDestFile); // get rid of it
  138.                         return(false);
  139.                     }
  140.                 }
  141.                 else
  142.                 {
  143.                     break;
  144.                 }
  145.             }
  146.             fclose(hDecompFile);
  147.         }
  148.         if (unzCloseCurrentFile(hFile) == UNZ_CRCERROR) // problem
  149.         {
  150.             return(false);
  151.         }
  152.     }
  153.     return(true); // not an error, means we're not going to install a directory!
  154. }
  155.  
  156.  
  157.  
  158. // used by routine
  159. void XMLHandler_InspectAutorun(byte bMsg,char *lpszData,unsigned long ulLen,LPARAM lParam)
  160. {
  161.     static byte s_bDepth; // depth of script. not really used the way you think it's used :)
  162.     static char s_szElement[32]; // long enough
  163.  
  164.     switch(bMsg)
  165.     {
  166.         case XMLPARSER_NOTIFY_STARTELEMENT:
  167.         {
  168.             if (s_bDepth == 2) // inside autorun
  169.             {
  170.                 // remember the element type
  171.                 if (ulLen < 32) // just the right size
  172.                 {
  173.                     strncpy(s_szElement,lpszData,ulLen);
  174.                     s_szElement[ulLen] = '\0';
  175.  
  176.                     AUTORUN_INFO *pARInfo = (AUTORUN_INFO*)lParam;
  177.                     // if we *haven't* finished finding an autorun section yet (we limit to one)
  178.                     if ((!(pARInfo->bState & 1)) && (lstrcmpi(s_szElement,"document") == 0)) // document
  179.                     {
  180.                         pARInfo->bState |= 2; // document
  181.                     }
  182.                 }
  183.                 else
  184.                 {
  185.                     s_szElement[0] = '\0'; // no element, can't be (our tags are shorter)
  186.                 }
  187.             }
  188.             else if (_strnicmp(lpszData,"installscript",ulLen) == 0) // going into script
  189.             {
  190.                 if (s_bDepth == 0)
  191.                 {
  192.                     s_bDepth++;
  193.                 }
  194.             }
  195.             else if (_strnicmp(lpszData,"autorun",ulLen) == 0) // autorun section
  196.             {
  197.                 if (s_bDepth == 1)
  198.                 {
  199.                     s_bDepth++;
  200.                 }
  201.             }
  202.         } break;
  203.         case XMLPARSER_NOTIFY_ENDELEMENT:
  204.         {
  205.             if (_strnicmp(lpszData,"installscript",ulLen) == 0) // done with installscript
  206.             {
  207.                 if (s_bDepth == 1)
  208.                 {
  209.                     s_bDepth--;
  210.                 }
  211.             }
  212.             else if (_strnicmp(lpszData,"autorun",ulLen) == 0) // done with autorun
  213.             {
  214.                 if (s_bDepth == 2)
  215.                 {
  216.                     s_bDepth--;
  217.  
  218.                     ((AUTORUN_INFO*)lParam)->bState |= 1; // finished an autorun section
  219.                 }
  220.             }
  221.         } break;
  222.         case XMLPARSER_NOTIFY_DATA:
  223.         {
  224.             if ((s_bDepth == 2) && (ulLen > 0)) // do we have info in there?
  225.             {
  226.                 AUTORUN_INFO *pARInfo = (AUTORUN_INFO*)lParam;
  227.                 // make sure we only have one file!!
  228.                 if ((pARInfo->lpFilename == NULL) && (!(pARInfo->bState & 1)) && (lstrcmpi(s_szElement,"file") == 0))
  229.                 {
  230.                     pARInfo->lpFilename = new char[ulLen + 1];
  231.                     lstrcpyn(pARInfo->lpFilename,lpszData,ulLen+1);
  232.                     Switch_Slashes(pARInfo->lpFilename,true); // switch slashes (to slashes)
  233.                 }
  234.             }
  235.         } break;
  236.     }
  237. }
  238.  
  239.  
  240.  
  241. // used by routine
  242. void XMLHandler_GetFilesPackages(byte bMsg,char *lpszData,unsigned long ulLen,LPARAM lParam)
  243. {
  244.     static byte s_bDepth; // depth of script. not really used the way you think it's used :)
  245.     static char s_szElement[32]; // long enough
  246.     static bool s_fOptional;
  247.     // files are first added to the WORKER_FILELIST list
  248.     // if they should be added to final, then they are added to master list
  249.     static GENERAL_FILELIST *s_pFileList;
  250.  
  251.     switch(bMsg)
  252.     {
  253.         case XMLPARSER_NOTIFY_STARTELEMENT:
  254.         {
  255.             if (s_bDepth == 2) // inside packageinfo
  256.             {
  257.                 // remember the element type
  258.                 if (ulLen < 32) // just the right size
  259.                 {
  260.                     strncpy(s_szElement,lpszData,ulLen);
  261.                     s_szElement[ulLen] = '\0';
  262.  
  263.                     if (lstrcmpi(s_szElement,"optional") == 0) // optional
  264.                     {
  265.                         s_fOptional = true;
  266.                     }
  267.                 }
  268.                 else
  269.                 {
  270.                     s_szElement[0] = '\0'; // no element, can't be (our tags are shorter)
  271.                 }
  272.             }
  273.             else if (_strnicmp(lpszData,"installscript",ulLen) == 0) // going into script
  274.             {
  275.                 if (s_bDepth == 0)
  276.                 {
  277.                     s_bDepth++;
  278.                 }
  279.             }
  280.             else if (_strnicmp(lpszData,"packageinfo",ulLen) == 0) // packageinfo realm
  281.             {
  282.                 s_fOptional = false;
  283.                 s_pFileList = NULL;
  284.  
  285.                 if (s_bDepth == 1)
  286.                 {
  287.                     s_bDepth++;
  288.                 }
  289.             }
  290.         } break;
  291.         case XMLPARSER_NOTIFY_ENDELEMENT:
  292.         {
  293.             if (_strnicmp(lpszData,"installscript",ulLen) == 0) // done with installscript
  294.             {
  295.                 if (s_bDepth == 1)
  296.                 {
  297.                     s_bDepth--;
  298.                 }
  299.             }
  300.             else if (_strnicmp(lpszData,"packageinfo",ulLen) == 0) // done with packageinfo
  301.             {
  302.                 if (s_bDepth == 2)
  303.                 {
  304.                     s_bDepth--;
  305.                     // OK, now...
  306.                     // we add the list from s_pFileList
  307.                     // to the list given by the caller
  308.                     // the temp list is then deleted - correction - it's not deleted, just added to the master list
  309.                     // no dupe checks are made, that's up to the initial probe
  310.                     XMLINSTALLER_EXTRAINFO *pExtraInfo = (XMLINSTALLER_EXTRAINFO*)lParam;
  311.  
  312.                     if (s_pFileList == NULL) // ? no files!
  313.                     {
  314.                         Cleanup_FileList(&s_pFileList);
  315.                     }
  316.                     else if ((pExtraInfo->bSolution == 2) && (s_fOptional)) // mismatch, this is optional, we only install main
  317.                     {
  318.                         // cleanup
  319.                         Cleanup_FileList(&s_pFileList);
  320.                     }
  321.                     else // ok we give the caller the list we got. we just add it to the end of the current list.
  322.                     {
  323.                         // add it in
  324.                         if (pExtraInfo->pFileList == NULL) // empty
  325.                         {
  326.                             pExtraInfo->pFileList = s_pFileList;
  327.                         }
  328.                         else
  329.                         {
  330.                             GENERAL_FILELIST *pCur = pExtraInfo->pFileList;
  331.                             while (pCur->next != NULL) { pCur = pCur->next; }
  332.  
  333.                             // pCur->next is insertion point
  334.                             pCur->next = s_pFileList;
  335.                         }
  336.                         s_pFileList = NULL; // clear local pointer
  337.                     }
  338.                 }
  339.             }
  340.         } break;
  341.         case XMLPARSER_NOTIFY_DATA:
  342.         {
  343.             if ((s_bDepth == 2) && (ulLen > 0)) // do we have info in there?
  344.             {
  345.                 if (lstrcmpi(s_szElement,"file") == 0) // author, let's get it
  346.                 {
  347.                     GENERAL_FILELIST *node = new GENERAL_FILELIST;
  348.                     node->lpFilename = new char[ulLen + 1];
  349.                     lstrcpyn(node->lpFilename,lpszData,ulLen+1);
  350.                     Switch_Slashes(node->lpFilename,true); // switch slashes (to slashes)
  351.  
  352.                     // add to list
  353.                     node->next = s_pFileList;
  354.                     s_pFileList = node;
  355.                 }
  356.             }
  357.         } break;
  358.     }
  359. }
  360.  
  361.  
  362.  
  363. // used by dialog
  364. void XMLHandler_ProbePackages(byte bMsg,char *lpszData,unsigned long ulLen,LPARAM lParam)
  365. {
  366.     static byte s_bDepth; // depth of script. not really used the way you think it's used :)
  367.     static char s_szElement[32]; // long enough
  368.     static PS_PACKAGEINFO s_PackageInfo; // package info - zeroed every new package
  369.     static PS_FILELIST *s_pFileList; // per-package
  370.  
  371.     switch(bMsg)
  372.     {
  373.         case XMLPARSER_NOTIFY_STARTELEMENT:
  374.         {
  375.             if (s_bDepth == 2) // inside packageinfo
  376.             {
  377.                 // remember the element type
  378.                 if (ulLen < 32) // just the right size
  379.                 {
  380.                     strncpy(s_szElement,lpszData,ulLen);
  381.                     s_szElement[ulLen] = '\0';
  382.  
  383.                     if (lstrcmpi(s_szElement,"optional") == 0) // optional
  384.                     {
  385.                         s_PackageInfo.fOptional = true;
  386.                     }
  387.                 }
  388.                 else
  389.                 {
  390.                     s_szElement[0] = '\0'; // no element, can't be (our tags are shorter)
  391.                 }
  392.             }
  393.             else if (_strnicmp(lpszData,"installscript",ulLen) == 0) // going into script
  394.             {
  395.                 if (s_bDepth == 0)
  396.                 {
  397.                     s_bDepth++;
  398.                 }
  399.             }
  400.             else if (_strnicmp(lpszData,"packageinfo",ulLen) == 0) // packageinfo realm
  401.             {
  402.                 ZeroMemory(&s_PackageInfo,sizeof(PS_PACKAGEINFO));
  403.                 s_pFileList = NULL;
  404.  
  405.                 if (s_bDepth == 1)
  406.                 {
  407.                     s_bDepth++;
  408.                 }
  409.             }
  410.         } break;
  411.         case XMLPARSER_NOTIFY_ENDELEMENT:
  412.         {
  413.             if (_strnicmp(lpszData,"installscript",ulLen) == 0) // done with installscript
  414.             {
  415.                 if (s_bDepth == 1)
  416.                 {
  417.                     s_bDepth--;
  418.                 }
  419.             }
  420.             else if (_strnicmp(lpszData,"packageinfo",ulLen) == 0) // done with packageinfo
  421.             {
  422.                 if (s_bDepth == 2)
  423.                 {
  424.                     s_bDepth--;
  425.  
  426.                     XMLPROBE_SCRIPTINFO *pScriptInfo = (XMLPROBE_SCRIPTINFO*)lParam;
  427.  
  428. //                    if (s_pFileList == NULL) // ? no files!
  429. //                    {
  430. //                        MessageBox(NULL,"Argg!!","bla",0);
  431. //                    }
  432. //                    else
  433.                     if (s_pFileList != NULL)
  434.                     {
  435.                         // add it in
  436.                         if (s_PackageInfo.lpTitle == NULL) // argg, bad!
  437.                         {
  438.                             s_PackageInfo.lpTitle = new char[lstrlen(DEFAULT_PACKAGENAME) + 1];
  439.                             lstrcpy(s_PackageInfo.lpTitle,DEFAULT_PACKAGENAME);
  440.                         }
  441.  
  442.                         // ok let's see where is this supposed to go
  443.                         // go through current packages
  444.                         WORD wInsertPos = (WORD)SendMessage(pScriptInfo->hwndCtrl,PSM_GETPACKAGECOUNT,0,0);
  445.                         for (WORD index=0,iCount = wInsertPos;index < iCount;index++)
  446.                         {
  447.                             PS_PACKAGEINFO *pPackageInfo = (PS_PACKAGEINFO*)SendMessage(pScriptInfo->hwndCtrl,PSM_GETPACKAGEINFO,index,0);
  448.  
  449.                             if (pPackageInfo->fOptional == s_PackageInfo.fOptional) // same. comparison is by name
  450.                             {
  451.                                 if (lstrcmpi(pPackageInfo->lpTitle,s_PackageInfo.lpTitle) >= 0) // insert here
  452.                                 {
  453.                                     wInsertPos = index;
  454.                                     break;
  455.                                 }
  456.                             }
  457.                             else if (pPackageInfo->fOptional) // remote package is optional, insert here
  458.                             {
  459.                                 wInsertPos = index;
  460.                                 break;
  461.                             }
  462.                         }
  463.  
  464.                         WORD wPackageID = (WORD)SendMessage(pScriptInfo->hwndCtrl,PSM_ADDPACKAGE,wInsertPos,(LPARAM)&s_PackageInfo);
  465.  
  466.                         PS_FILELIST *pCur = s_pFileList;
  467.                         while (pCur != NULL)
  468.                         {
  469.                             SendMessage(pScriptInfo->hwndCtrl,PSM_ADDFILE,wPackageID,(LPARAM)&(pCur->fileInfo));
  470.                             pCur = pCur->next;
  471.                         }
  472.                     }
  473.  
  474.                     // then clear it...
  475.                     PS_FILELIST *pCur = s_pFileList;
  476.                     while (pCur != NULL)
  477.                     {
  478.                         PS_FILELIST *pNext = pCur->next;
  479.                         delete pCur;
  480.                         pCur = pNext;
  481.                     }
  482.  
  483.                     // NOTE we DO NOT delete the allocated title nor filename! that's up to the package selector
  484.                 }
  485.             }
  486.         } break;
  487.         case XMLPARSER_NOTIFY_DATA:
  488.         {
  489.             if ((s_bDepth == 2) && (ulLen > 0)) // do we have info in there?
  490.             {
  491.                 if (lstrcmpi(s_szElement,"title") == 0) // name of package
  492.                 {
  493.                     s_PackageInfo.lpTitle = new char[ulLen + 1];
  494.                     lstrcpyn(s_PackageInfo.lpTitle,lpszData,ulLen+1);
  495.                 }
  496.                 else if (lstrcmpi(s_szElement,"file") == 0) // author, let's get it
  497.                 {
  498.                     XMLPROBE_SCRIPTINFO *pScriptInfo = (XMLPROBE_SCRIPTINFO*)lParam;
  499.  
  500.                     PS_FILELIST *node = new PS_FILELIST;
  501.                     node->fileInfo.lpFilename = new char[ulLen + 1];
  502.                     lstrcpyn(node->fileInfo.lpFilename,lpszData,ulLen+1);
  503.                     node->fileInfo.dwFileSize = 0; // init
  504.                     // now we *try* to find this file we got, and find its size
  505.                     // no need to remember our current position
  506.  
  507.                     // before we do anything, let's switch slashes
  508.                     // remember this is from the script, this will turn any backslashes to slashes
  509.                     Switch_Slashes(node->fileInfo.lpFilename,true);
  510.                     if (unzLocateFile(pScriptInfo->hFile,node->fileInfo.lpFilename,2) == UNZ_OK) // try to find the file
  511.                     {
  512.                         // got it
  513.                         unz_file_info fileInfo;
  514.                         unzGetCurrentFileInfo(pScriptInfo->hFile,&fileInfo,NULL,0,NULL,0,NULL,0); // we need its size
  515.                         node->fileInfo.dwFileSize = fileInfo.uncompressed_size;
  516.                     }
  517.  
  518.                     // now switch back to backslashes
  519.                     Switch_Slashes(node->fileInfo.lpFilename,false);
  520.  
  521.                     // add to list (always at beginning)
  522.                     node->next = s_pFileList;
  523.                     s_pFileList = node;
  524.                 }
  525.             }
  526.         } break;
  527.     }
  528. }
  529.  
  530.  
  531.  
  532. INT_PTR CALLBACK PackagesDlgProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
  533. {
  534.     switch(uMsg)
  535.     {
  536.         case WM_INITDIALOG:
  537.         {
  538.             PACKAGEDLG_EXTRAINFO *pExtraInfo = (PACKAGEDLG_EXTRAINFO*)lParam;
  539.             SetWindowLongPtr(hwndDlg,GWLP_USERDATA,(LONG_PTR)pExtraInfo);
  540.  
  541.             XMLPROBE_SCRIPTINFO *pScriptInfo = new XMLPROBE_SCRIPTINFO;
  542.             pScriptInfo->hFile = pExtraInfo->hFile;
  543.             pScriptInfo->hwndCtrl = GetDlgItem(hwndDlg,IDC_PACKAGEDLG_SELECTOR);
  544.  
  545.             // ok now process script
  546.             XMLParser_FeedDocument(XMLHandler_ProbePackages,pExtraInfo->lpScript,(LPARAM)pScriptInfo);
  547.  
  548.             delete pScriptInfo;
  549.  
  550.             // ok now finish off the rest of the dialog
  551.             char szTitle[128], szFormatted[256]; // big enough
  552.             GetDlgItemText(hwndDlg,IDC_PACKAGEDLG_TITLE,szTitle,512);
  553.             wsprintf(szFormatted,Translate(szTitle),pExtraInfo->szFilename); // format filename into string
  554.             SetDlgItemText(hwndDlg,IDC_PACKAGEDLG_TITLE,szFormatted);
  555.  
  556.             // select all as default
  557.             SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_INSTALLALL,BM_CLICK,0,0); // simulate a click (selection)
  558.  
  559.             // now go through all packages and set dialog info
  560.             // this info *could* be received by caller, but this is a better approach, in a sense
  561.             WORD wMainFiles = 0, wAllFiles = 0;
  562.             DWORD dwMainSize = 0, dwAllSize = 0;
  563.             for (WORD index=0, wCount = (WORD)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETPACKAGECOUNT,0,0);index < wCount;index++)
  564.             {
  565.                 PS_PACKAGEINFO *pPackageInfo = (PS_PACKAGEINFO*)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETPACKAGEINFO,index,0);
  566.  
  567.                 WORD wPackageFiles = (WORD)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETFILECOUNT,index,0);
  568.                 DWORD dwPackageSize = 0;
  569.  
  570.                 // calc package size
  571.                 for (WORD index2=0;index2 < wPackageFiles;index2++)
  572.                 {
  573.                     PS_FILEINFO *pFileInfo = (PS_FILEINFO*)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETFILEINFO,index2,(LPARAM)pPackageInfo);
  574.                     dwPackageSize += pFileInfo->dwFileSize;
  575.                 }
  576.  
  577.                 if (!pPackageInfo->fOptional)
  578.                 {
  579.                     wMainFiles += wPackageFiles;
  580.                     dwMainSize += dwPackageSize;
  581.                 }
  582.                 wAllFiles += wPackageFiles;
  583.                 dwAllSize += dwPackageSize;
  584.             }
  585.  
  586.             char szTemp[128], szFileSize[32];
  587.             Format_DisplaySize(szFileSize,dwAllSize);
  588.             wsprintf(szTemp,Translate("%d file/s (%s)"),wAllFiles,szFileSize);
  589.             SetDlgItemText(hwndDlg,IDC_PACKAGEDLG_STATIC_ALLINFO,szTemp);
  590.  
  591.             Format_DisplaySize(szFileSize,dwMainSize);
  592.             wsprintf(szTemp,Translate("%d file/s (%s)"),wMainFiles,szFileSize);
  593.             SetDlgItemText(hwndDlg,IDC_PACKAGEDLG_STATIC_MAININFO,szTemp);
  594.  
  595.             if (wMainFiles == wAllFiles) // no optional packages
  596.             {
  597.                 // having both enabled, even though we don't have optional packages will give problems
  598.                 // this is just a quick workaround, but it's best this way
  599.                 EnableWindow(GetDlgItem(hwndDlg,IDC_PACKAGEDLG_INSTALLMAIN),false); // avoid mixups
  600.                 EnableWindow(GetDlgItem(hwndDlg,IDC_PACKAGEDLG_STATIC_MAININFO),false); // avoid mixups
  601.             }
  602.  
  603.             // clean up is done on destruction of dialog
  604.             LP_TranslateDialog(hwndDlg);
  605.             return(true);
  606.         } break;
  607.         case WM_COMMAND:
  608.         {
  609.             if (HIWORD(wParam) == BN_CLICKED) // If we clicked
  610.             {
  611.                 switch (LOWORD(wParam)) 
  612.                 {
  613.                     case IDOK:
  614.                     {
  615.                         // start installing
  616.                         PACKAGEDLG_EXTRAINFO *pExtraInfo = (PACKAGEDLG_EXTRAINFO*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
  617.  
  618.                         unzFile hFile = pExtraInfo->hFile;
  619.                         // go through selected packages and copy filenames to be installed
  620.                         for (WORD index=0, wCount = (WORD)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETPACKAGECOUNT,0,0);index < wCount;index++)
  621.                         {
  622.                             PS_PACKAGEINFO *pPackageInfo = (PS_PACKAGEINFO*)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETPACKAGEINFO,index,0);
  623.  
  624.                             if (pPackageInfo->fSelected) // selected
  625.                             {
  626.                                 for (WORD index2 = 0, wFileCount = (WORD)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETFILECOUNT,index,0);index2 < wFileCount;index2++)
  627.                                 {
  628.                                     PS_FILEINFO *pFileInfo = (PS_FILEINFO*)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETFILEINFO,index2,(LPARAM)pPackageInfo);
  629.  
  630.                                     GENERAL_FILELIST *node = new GENERAL_FILELIST;
  631.                                     node->lpFilename = new char[lstrlen(pFileInfo->lpFilename) + 1];
  632.                                     lstrcpy(node->lpFilename,pFileInfo->lpFilename);
  633.  
  634.                                     // add it
  635.                                     node->next = pExtraInfo->pFileList;
  636.                                     pExtraInfo->pFileList = node;
  637.                                 }
  638.                             }
  639.                         }
  640.  
  641.                         // return solution type
  642.                         EndDialog(hwndDlg,((IsWindowEnabled(GetDlgItem(hwndDlg,IDC_PACKAGEDLG_DOTHESAME))) && (IsDlgButtonChecked(hwndDlg,IDC_PACKAGEDLG_DOTHESAME) == BST_CHECKED)) ? (((IsDlgButtonChecked(hwndDlg,IDC_PACKAGEDLG_INSTALLALL) == BST_CHECKED) ? (1) : (((IsDlgButtonChecked(hwndDlg,IDC_PACKAGEDLG_INSTALLMAIN) == BST_CHECKED) ? (2) : (0))))) : (0));
  643.                         return(true);
  644.                     } break;
  645.                     case IDCANCEL:
  646.                     {
  647.                         // return (we cancel!)
  648.                         EndDialog(hwndDlg,0xFF);
  649.                         return(true);
  650.                     } break;
  651.                     case IDC_PACKAGEDLG_INSTALLALL:
  652.                     case IDC_PACKAGEDLG_INSTALLMAIN:
  653.                     {
  654.                         // select appropriate packages from control
  655.                         for (WORD index=0, wCount = (WORD)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETPACKAGECOUNT,0,0);index < wCount;index++)
  656.                         {
  657.                             PS_PACKAGEINFO *pPackageInfo = (PS_PACKAGEINFO*)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETPACKAGEINFO,index,0);
  658.  
  659.                             bool fSelect = true;
  660.                             if ((pPackageInfo->fOptional) && (LOWORD(wParam) != IDC_PACKAGEDLG_INSTALLALL)) // we don't install all
  661.                             {
  662.                                 fSelect = false;
  663.                             }
  664.                             SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_SELECTPACKAGE,index,fSelect);
  665.                         }
  666.  
  667.                         SendMessage(hwndDlg,PSN_PACKAGESELCHANGE,0,0); // handle change (not done for us)
  668.                         return(true);
  669.                     } break;
  670.                 }
  671.             }
  672.         } break;
  673.         case PSN_PACKAGESELCHANGE: // change in selection
  674.         {
  675.             // check selection state
  676.             bool fMainOnly = true;
  677.             WORD wSelectCount = 0, wSelectFiles = 0, wTotalFiles = 0;
  678.             DWORD dwSelectSize = 0, dwTotalSize = 0;
  679.             for (WORD index=0, wCount = (WORD)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETPACKAGECOUNT,0,0);index < wCount;index++)
  680.             {
  681.                 PS_PACKAGEINFO *pPackageInfo = (PS_PACKAGEINFO*)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETPACKAGEINFO,index,0);
  682.                 WORD wFileCount = (WORD)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETFILECOUNT,index,0);
  683.  
  684.                 wTotalFiles += wFileCount;
  685.                 if (pPackageInfo->fSelected)
  686.                 {
  687.                     wSelectCount++;
  688.                     if (pPackageInfo->fOptional) // optional, selected?
  689.                     {
  690.                         fMainOnly = false;
  691.                     }
  692.  
  693.                     // calc package size
  694.                     wSelectFiles += wFileCount;
  695.                 }
  696.  
  697.                 for (WORD index2 = 0;index2 < wFileCount;index2++)
  698.                 {
  699.                     PS_FILEINFO *pFileInfo = (PS_FILEINFO*)SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETFILEINFO,index2,(LPARAM)pPackageInfo);
  700.  
  701.                     if (pPackageInfo->fSelected)
  702.                     {
  703.                         dwSelectSize += pFileInfo->dwFileSize;
  704.                     }
  705.                     dwTotalSize += pFileInfo->dwFileSize;
  706.                 }
  707.             }
  708.  
  709.             bool fSelectAll = false, fSelectMain = false; // are we selecting all?
  710.             if (wSelectCount != 0) // we got smt
  711.             {
  712.                 if (wSelectCount == wCount) // total (won't compile on non-VC, damn MS and their non-ANSI crap)
  713.                 {
  714.                     fSelectAll = true;
  715.                 }
  716.                 else if (fMainOnly)
  717.                 {
  718.                     fSelectMain = true;
  719.                 }
  720.  
  721.                 if (!IsWindowEnabled(GetDlgItem(hwndDlg,IDC_PACKAGEDLG_INSTALLMAIN)))
  722.                 {
  723.                     fSelectMain = false;
  724.                 }
  725.             }
  726.             else // uncheck both buttons
  727.             {
  728.                 fSelectAll = false;
  729.                 fSelectMain = false;
  730.             }
  731.  
  732.             // we don't use CheckRadioButton() coz both buttons might be unselected
  733.             SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_INSTALLALL,BM_SETCHECK,((fSelectAll) ? (BST_CHECKED) : (BST_UNCHECKED)),0);
  734.             SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_INSTALLMAIN,BM_SETCHECK,((fSelectMain) ? (BST_CHECKED) : (BST_UNCHECKED)),0);
  735.  
  736.             // if one of these, then we can save it
  737.             EnableWindow(GetDlgItem(hwndDlg,IDC_PACKAGEDLG_DOTHESAME),fSelectAll || fSelectMain);
  738.             // enable or disable accordingly
  739.             EnableWindow(GetDlgItem(hwndDlg,IDOK),wSelectCount != 0);
  740.  
  741.             // ok now show some info about our selection
  742.             char szTemp[32], szTemp2[32], szTemp3[128]; // not the best choice for variables naming, hehe :)
  743.             // package num
  744.             wsprintf(szTemp,"%d/%d",wSelectCount,SendDlgItemMessage(hwndDlg,IDC_PACKAGEDLG_SELECTOR,PSM_GETPACKAGECOUNT,0,0));
  745.             SetDlgItemText(hwndDlg,IDC_PACKAGEDLG_STATIC_SELPACKAGES,szTemp);
  746.  
  747.             // size
  748.             Format_DisplaySize(szTemp,dwSelectSize);
  749.             Format_DisplaySize(szTemp2,dwTotalSize);
  750.             wsprintf(szTemp3,"%s/%s",szTemp,szTemp2);
  751.             SetDlgItemText(hwndDlg,IDC_PACKAGEDLG_STATIC_SELSIZE,szTemp3);
  752.  
  753.             // file count
  754.             wsprintf(szTemp,"%d/%d",wSelectFiles,wTotalFiles);
  755.             SetDlgItemText(hwndDlg,IDC_PACKAGEDLG_STATIC_SELFILES,szTemp);
  756.             return(true);
  757.         } break;
  758.         case WM_CLOSE:
  759.         {
  760.             // return type
  761.             EndDialog(hwndDlg,0xFF);
  762.             return(true);
  763.         } break;
  764.     }
  765.     return(false);
  766. }
  767.  
  768.  
  769.  
  770. // returns true on good
  771. // returns false on bad
  772. // :)
  773. // bInstallSolution is given by reference
  774. // needs to be changeable
  775. // but pointers are getting annoying :)
  776. // returns:
  777. // 0 - good
  778. // 1 - error
  779. // 2 - cancel
  780. __forceinline byte Extract_File(HWND hwndDlg,int iItemID,byte &bInstallSolution,const char *szSrcFile,const char *szDestDir)
  781. {
  782.     unzFile hFile = unzOpen(szSrcFile);
  783.  
  784.     if (hFile != NULL)
  785.     {
  786.         // hmm this used to work different
  787.         // now it works this way: script is loaded here, and unloaded when done
  788.         // in a nutshell: it's only loaded once for the installation process, which is good :)
  789.         if (unzLocateFile(hFile,INSTALLSCRIPT_FILENAME,2) == UNZ_OK) // try to find the installation script (insensitive)
  790.         {
  791.             // we got a script!
  792.             // with l_bInstallSolution 0 - ask user with dialog, 1 - all, 2 - main
  793.             unz_file_info fileInfo;
  794.             unzGetCurrentFileInfo(hFile,&fileInfo,NULL,0,NULL,0,NULL,0); // we need its size
  795.  
  796.             if (fileInfo.uncompressed_size > 0) // valid
  797.             {
  798.                 if (unzOpenCurrentFile(hFile) == UNZ_OK)
  799.                 {
  800.                     // how installation takes place:
  801.                     // 1. through the packages dialog - the dialog lets the user chooose
  802.                     //    what packages he/she wants to install. The dialog returns a
  803.                     //    WORKER_FILELIST* list
  804.                     // 2. through parser handler - the parser receives the installation
  805.                     //    solution hint, and forms a WORKER_FILELIST* list accordingly
  806.                     char szPackages[32];
  807.                     WORD wPackagesCount; // if we only have one package to install
  808.  
  809.                     ListView_GetItemText(GetDlgItem(hwndDlg,IDC_INSTALLATIONS),iItemID,4,szPackages,32);
  810.                     wPackagesCount = atoi(strchr(szPackages,'/')+1);
  811.  
  812.                     // find info on all packages and get it in the selection control
  813.                     char *lpScriptBuffer = new char[fileInfo.uncompressed_size + 1];
  814.  
  815.                     // the script can't be that big
  816.                     // that's the basic assumption here
  817.                     int iResult = unzReadCurrentFile(hFile,lpScriptBuffer,fileInfo.uncompressed_size);
  818.  
  819.                     if (iResult < 0) // error
  820.                     {
  821.                         // no script, some error
  822.                         delete [] lpScriptBuffer;
  823.                         unzCloseCurrentFile(hFile);
  824.                         unzClose(hFile);
  825.                         return(1);
  826.                     }
  827.  
  828.                     if (unzCloseCurrentFile(hFile) == UNZ_CRCERROR)
  829.                     {
  830.                         // no script, CRC error
  831.                         delete [] lpScriptBuffer;
  832.                         unzClose(hFile);
  833.                         return(1);
  834.                     }
  835.  
  836.                     lpScriptBuffer[fileInfo.uncompressed_size] = '\0'; // close it
  837.  
  838.  
  839.                     if ((!bInstallSolution) && (wPackagesCount > 1))
  840.                     {
  841.                         // installation solution is returned (used for more packages later, if needed)
  842.                         // all the dialog has to do, is read the current open file (the script is already positioned, it only has to be read)
  843.                         PACKAGEDLG_EXTRAINFO *pExtraInfo = new PACKAGEDLG_EXTRAINFO; // deleted by us after dialog dies
  844.                         pExtraInfo->hFile = hFile;
  845.                         pExtraInfo->szFilename = strrchr(szSrcFile,'\\') + 1;
  846.                         pExtraInfo->pFileList = NULL;
  847.                         pExtraInfo->lpScript = lpScriptBuffer;
  848.                         byte bResult = DialogBoxParam(g_hInstance,MAKEINTRESOURCE(IDD_PACKAGESDIALOG),hwndDlg,PackagesDlgProc,(LPARAM)pExtraInfo);
  849.  
  850.                         if (bResult == 0xFF)
  851.                         {
  852.                             // we don't install, let's leave (user hit Cancel)
  853.  
  854.                             // clean up
  855.                             Cleanup_FileList(&(pExtraInfo->pFileList));
  856.  
  857.                             delete pExtraInfo;
  858.                             delete [] lpScriptBuffer;
  859.                             unzClose(hFile);
  860.  
  861.                             return(2);
  862.                         }
  863.                         else
  864.                         {
  865.                             bInstallSolution = bResult;
  866.                         }
  867.  
  868.                         // okay, now we have our installation list
  869.                         // we *always* have installation files
  870.                         // no way did we come all this way and we can't install this :)
  871.                         bool fError = false;
  872.                         GENERAL_FILELIST *pFileList = pExtraInfo->pFileList;
  873.                         while (pFileList != NULL)
  874.                         {
  875.                             // backslashes to slashes
  876.                             Switch_Slashes(pFileList->lpFilename,true);
  877.                             // no need to switch slashes here, control items were already switched
  878.                             if (unzLocateFile(hFile,pFileList->lpFilename,2) != UNZ_OK) // try to find the file
  879.                             {
  880.                                 fError = true;
  881.                                 break; // argg
  882.                             }
  883.  
  884.                             if (!Worker_InstallFile(hFile,hwndDlg,iItemID,szDestDir)) // error has occured
  885.                             {
  886.                                 fError = true;
  887.                                 break; // stop installing (we don't give a warning here, the user already got it)
  888.                             }
  889.                             pFileList = pFileList->next;
  890.                         }
  891.  
  892.                         // clean up
  893.                         Cleanup_FileList(&(pExtraInfo->pFileList));
  894.  
  895.                         delete pExtraInfo;
  896.  
  897.                         if (fError)
  898.                         {
  899.                             delete [] lpScriptBuffer;
  900.                             unzClose(hFile);
  901.                             return(1);
  902.                         }
  903.                     }
  904.                     else // install all (or just one package), or main
  905.                     {
  906.                         // call XML handler
  907.                         XMLINSTALLER_EXTRAINFO *pExtraInfo = new XMLINSTALLER_EXTRAINFO;
  908.                         pExtraInfo->bSolution = (((bInstallSolution == 1) || (wPackagesCount == 1)) ? (1) : (2)); // or one package/all, or main
  909.                         pExtraInfo->pFileList = NULL;
  910.  
  911.                         // ok now process script
  912.                         XMLParser_FeedDocument(XMLHandler_GetFilesPackages,lpScriptBuffer,(DWORD)pExtraInfo);
  913.  
  914.                         // start installing
  915.                         GENERAL_FILELIST *pFileList = pExtraInfo->pFileList;
  916.                         bool fError = false;
  917.                         while (pFileList != NULL)
  918.                         {
  919.                             // backslashes to slashes
  920.                             Switch_Slashes(pFileList->lpFilename,true);
  921.                             if (unzLocateFile(hFile,pFileList->lpFilename,2) != UNZ_OK) // try to find the file
  922.                             {
  923.                                 fError = true;
  924.                                 break; // argg
  925.                             }
  926.  
  927.                             if (!Worker_InstallFile(hFile,hwndDlg,iItemID,szDestDir))
  928.                             {
  929.                                 fError = true;
  930.                                 break;
  931.                             }
  932.                             pFileList = pFileList->next;
  933.                         }
  934.  
  935.                         // ok now we have everything
  936.                         Cleanup_FileList(&(pExtraInfo->pFileList));
  937.  
  938.                         delete pExtraInfo;
  939.  
  940.                         if (fError)
  941.                         {
  942.                             delete [] lpScriptBuffer;
  943.                             unzClose(hFile);
  944.                             return(1);
  945.                         }
  946.                     }
  947.                     // autorun goes here
  948.                     // here we try to use autorun section
  949.                     AUTORUN_INFO *pARInfo = new AUTORUN_INFO;
  950.                     pARInfo->lpFilename = NULL;
  951.                     pARInfo->bState = 0;
  952.                     XMLParser_FeedDocument(XMLHandler_InspectAutorun,lpScriptBuffer,(DWORD)pARInfo);
  953.  
  954.                     // handle it
  955.                     if ((pARInfo->bState & 1) && (pARInfo->lpFilename != NULL)) // got it
  956.                     {
  957.                         if (unzLocateFile(hFile,pARInfo->lpFilename,2) == UNZ_OK) // found file
  958.                         {
  959.                             // check that filetype matches given type
  960.                             char *lpExtension = strrchr(pARInfo->lpFilename,'.') + 1; // extension
  961.                             if (lpExtension == NULL) // no extension
  962.                             {
  963.                                 pARInfo->bState &= ~2; // not a document, AFAIK
  964.                             }
  965.                             if ((pARInfo->bState & 2) && (!((lstrcmpi(lpExtension,"txt") == 0) || (lstrcmpi(lpExtension,"htm") == 0) || (lstrcmpi(lpExtension,"html") == 0))))
  966.                             {
  967.                                 // NOT a document
  968.                                 pARInfo->bState &= ~2;
  969.                             }
  970.  
  971.                             bool fContinue = true;
  972.                             if ((!(pARInfo->bState & 2)) || (g_WorkOptions.dwFlags & 1)) // not a document, or, we always have to ask
  973.                             {
  974.                                 char szMsg[512];
  975.                                 Switch_Slashes(pARInfo->lpFilename,false); // switch it, to make it displayable
  976.                                 wsprintf(szMsg,Translate("The installation wants to autorun a file, named \"%s\". Would you like to run it?"),pARInfo->lpFilename);
  977.                                 if (MessageBox(hwndDlg,szMsg,Translate("Miranda Installer"),MB_YESNO | MB_ICONINFORMATION | MB_DEFBUTTON2) == IDNO) // default button is No, to avoid any fast clicks, being careful is good :)
  978.                                 {
  979.                                     fContinue = false;
  980.                                 }
  981.                                 else // switch back (needed later)
  982.                                 {
  983.                                     Switch_Slashes(pARInfo->lpFilename,true);
  984.                                 }
  985.                             }
  986.  
  987.                             if (fContinue) // move on
  988.                             {
  989.                                 // here we extract the file to a temp dir (with the same file extension)
  990.                                 // and run it
  991.                                 if (unzOpenCurrentFile(hFile) == UNZ_OK)
  992.                                 {
  993.                                     // build filename
  994.                                     char szDest[MAX_PATH+1];
  995.                                     GetTempPath(MAX_PATH+1,szDest);
  996.  
  997.                                     char *lpFilename = strrchr(pARInfo->lpFilename,'/');
  998.                                     if (lpFilename == NULL)
  999.                                     {
  1000.                                         lpFilename = pARInfo->lpFilename;
  1001.                                     }
  1002.                                     else
  1003.                                     {
  1004.                                         lpFilename++;
  1005.                                     }
  1006.                                     lstrcat(szDest,lpFilename); // only add the filename
  1007.  
  1008.                                     FILE *hARFile = fopen(szDest,"wb");
  1009.                                     if (hARFile != NULL)
  1010.                                     {
  1011.                                         char szData[2048];
  1012.                                         while (1)
  1013.                                         {
  1014.                                             int iRead = unzReadCurrentFile(hFile,szData,sizeof(szData));
  1015.  
  1016.                                             if (iRead > 0)
  1017.                                             {
  1018.                                                 if (fwrite(szData,1,iRead,hARFile) != (unsigned int)iRead)
  1019.                                                 {
  1020.                                                     break;
  1021.                                                 }
  1022.                                             }
  1023.                                             else
  1024.                                             {
  1025.                                                 break;
  1026.                                             }
  1027.                                         }
  1028.                                         fclose(hARFile);
  1029.                                     }
  1030.                                     unzCloseCurrentFile(hFile); // close the file (don't care about errors, we're done with this file)
  1031.                                     ShellExecute(NULL,"open",szDest,NULL,NULL,SW_SHOW);
  1032.                                 }
  1033.                             } // fContinue
  1034.                         } // found file in zip
  1035.                     }
  1036.  
  1037.                     if (pARInfo->lpFilename != NULL)
  1038.                     {
  1039.                         delete [] pARInfo->lpFilename;
  1040.                     }
  1041.                     delete pARInfo;
  1042.  
  1043.                     // done with script
  1044.                     delete [] lpScriptBuffer;
  1045.                 }
  1046.             }
  1047.         }
  1048.         else // we don't have a script
  1049.         {
  1050.             // perform a dirty, dirty installaion (file-by-file)
  1051.             if (unzGoToFirstFile(hFile) == UNZ_OK)
  1052.             {
  1053.                 do
  1054.                 {
  1055.                     if (!Worker_InstallFile(hFile,hwndDlg,iItemID,szDestDir))
  1056.                     {
  1057.                         unzClose(hFile);
  1058.                         return(1);
  1059.                     }
  1060.                 } while (unzGoToNextFile(hFile) == UNZ_OK);
  1061.             }
  1062.         }
  1063.  
  1064.         unzClose(hFile);
  1065.         return(0);
  1066.     }
  1067.     return(1);
  1068. }
  1069.  
  1070.  
  1071.  
  1072. DWORD WINAPI InstallerProc(LPVOID lpParameter)
  1073. {
  1074.     // about installing language packs - this is Kai's (kai_b) solution, works out great btw :)
  1075.     // language packs are installed in the "usual" language directory
  1076.     // if the whole "batch" of installations included a language pack installation, then
  1077.     // the user will be asked which one should be used (that is, only if more than one language pack is available)
  1078.     // the "active" language pack is also copied to the language directory (there's no need to remember it, because it'll be copied last/first, so we can "know" it's the active one)
  1079.     // this whole process isn't done here, it's done by the caller thread later
  1080.  
  1081.     // do checks for g_fStopThread
  1082.     HWND hwndDlg = (HWND)lpParameter;
  1083.     HWND hListView = GetDlgItem(hwndDlg,IDC_INSTALLATIONS);
  1084.  
  1085.     LVITEM lvItem;
  1086.     char *lpDestDir = NULL;
  1087.     char szPluginsDir[MAX_PATH + 1]; // *might* be needed
  1088.     lstrcpy(szPluginsDir,g_WorkOptions.szMirandaDirectory);
  1089.     lstrcat(szPluginsDir,"\\Plugins");
  1090.  
  1091.     SendMessage(hwndDlg,MIRINST_INFOMSG_STARTING,0,0);
  1092.     byte bInstallSolution = (byte)((g_WorkOptions.dwFlags & 6) >> 1); // init to setting from options
  1093.     bool fMasterError = false; // true if some error occured while installing
  1094.     for (int index=0, iCount=ListView_GetItemCount(hListView);index < iCount;index++)
  1095.     {
  1096.         if (g_fStopThread)
  1097.         {
  1098.             PostMessage(hwndDlg,MIRINST_INFOMSG_DONE,0,0);
  1099.             ExitThread(1);
  1100.         }
  1101.         lvItem.mask = LVIF_PARAM;
  1102.         lvItem.iSubItem = 0;
  1103.         lvItem.iItem = index;
  1104.         ListView_GetItem(hListView,&lvItem);
  1105.  
  1106.         ADDON_LISTINFO *pListInfo = (ADDON_LISTINFO*)lvItem.lParam;
  1107.  
  1108.         // work out the dest dir according to type
  1109.         switch(pListInfo->bType)
  1110.         {
  1111.             case INSTALLTYPE_PLUGIN: lpDestDir = szPluginsDir; break;
  1112.             case INSTALLTYPE_ICON: lpDestDir = g_WorkOptions.szIconDirectory; break;
  1113.             case INSTALLTYPE_SOUND: lpDestDir = g_WorkOptions.szSoundDirectory; break;
  1114.             case INSTALLTYPE_LANGUAGE: lpDestDir = g_WorkOptions.szLangDirectory; break;
  1115.             case INSTALLTYPE_TOOL: lpDestDir = g_WorkOptions.szToolDirectory; break;
  1116.             case INSTALLTYPE_SOURCE: lpDestDir = g_WorkOptions.szSrcDirectory; break;
  1117.             case INSTALLTYPE_DOC: lpDestDir = g_WorkOptions.szDocDirectory; break;
  1118.             case INSTALLTYPE_SKIN: lpDestDir = g_WorkOptions.szSkinDirectory; break;
  1119.             case INSTALLTYPE_NIGHTLY: lpDestDir = g_WorkOptions.szMirandaDirectory; break;
  1120.         }
  1121.  
  1122.         // great
  1123.         SendMessage(hwndDlg,MIRINST_INFOMSG_STARTITEM,index,0);
  1124.         byte bResult = Extract_File(hwndDlg,index,bInstallSolution,pListInfo->lpFilePath,lpDestDir); // install solution is changeable
  1125.         SendMessage(hwndDlg,MIRINST_INFOMSG_FINISHEDITEM,index,bResult); // we report an error
  1126.  
  1127.         if (bResult == 1)
  1128.         {
  1129.             fMasterError = true;
  1130.         }
  1131.         // any changes to listview items is done by the master window. bahh! :)
  1132.     }
  1133.     PostMessage(hwndDlg,MIRINST_INFOMSG_DONE,fMasterError,0);
  1134.     ExitThread(0);
  1135. }